package com.lemontree.mbg.plugins;

import static com.lemontree.mbg.support.Constant.SUPER_FILEDS;

import java.util.Arrays;
import java.util.List;

import com.sun.org.apache.bcel.internal.generic.InstructionListObserver;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.codegen.AbstractXmlGenerator;
import org.mybatis.generator.config.CommentGeneratorConfiguration;
import org.mybatis.generator.config.Context;

import com.lemontree.mbg.support.PropertiesUtil;

import tk.mybatis.mapper.generator.MapperCommentGenerator;

/**
 * @Author: Lemontree
 * @Description: 自定义通用mapper
 * @Date: 20:22 2018/5/7
 */
public class CustomClassPlugins extends PluginAdapter {
    // 注释生成器
    private CommentGeneratorConfiguration commentCfg;
    protected AbstractXmlGenerator sqlMapGenerator;

    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public void setContext(Context context) {
        // 设置默认的注释生成器
        commentCfg = new CommentGeneratorConfiguration();
        commentCfg.setConfigurationType(
                MapperCommentGenerator.class.getCanonicalName());
        context.setCommentGeneratorConfiguration(commentCfg);
        // 支持oracle获取注释#114
        context.getJdbcConnectionConfiguration()
                .addProperty("remarksReporting", "true");
    }

    @Override
    public boolean modelBaseRecordClassGenerated(
            TopLevelClass topLevelClass,
            IntrospectedTable introspectedTable) {
        generateClassAnnotation(topLevelClass);
        return true;
    }

    @Override
    public boolean modelFieldGenerated(Field field,
            TopLevelClass topLevelClass,
            IntrospectedColumn introspectedColumn,
            IntrospectedTable introspectedTable,
            ModelClassType modelClassType) {
        if(validateNormalField(field)) {
            return false;
        }
        generateStaticProField(field, introspectedColumn, topLevelClass);
        generateSuperClass(topLevelClass);
        generateFieldAnnotation(field, topLevelClass);
        return true;
    }

    @Override
    public boolean modelGetterMethodGenerated(Method method,
            TopLevelClass topLevelClass,
            IntrospectedColumn introspectedColumn,
            IntrospectedTable introspectedTable,
            ModelClassType modelClassType) {
        Field field = new Field();
        field.setName(introspectedColumn.getJavaProperty());
        return !validateNormalField(field);
    }

    @Override
    public boolean modelSetterMethodGenerated(Method method,
            TopLevelClass topLevelClass,
            IntrospectedColumn introspectedColumn,
            IntrospectedTable introspectedTable,
            ModelClassType modelClassType) {
        Field field = new Field();
        field.setName(introspectedColumn.getJavaProperty());
        return !validateNormalField(field);
    }

    /**
     * @Author: Lemontree
     * @Description: 判断该字段是否在{@code Constant#SUPER_FILEDS} 中出现，即去除父类中出现的字段
     * @param field
     * @Date: 0:09 2018/6/12
     */
    private boolean validateNormalField(Field field) {
        // 存在父类，去除公共部分字段，子类共用父类字段
        if(StringUtils.isNotBlank(PropertiesUtil.VAL_SUPER_CLASS)
                && SUPER_FILEDS.contains(field.getName())) {
            return true;
        }
        return false;
    }

    private void generateSuperClass(TopLevelClass topLevelClass) {
        // 导入超类
        if(StringUtils.isNotBlank(PropertiesUtil.VAL_SUPER_CLASS)) {
            topLevelClass.setSuperClass(PropertiesUtil.VAL_SUPER_CLASS);
            topLevelClass.addImportedType(
                    PropertiesUtil.VAL_SUPER_CLASS_PACKAGE);
        }
    }

    /**
     * @param field
     *            原始字段
     * @param introspectedColumn
     *            数据库字段
     * @param topLevelClass
     *            生成类
     * @Author: Lemontree
     * @Description: 为每个字段添加数据库查询的String字段，主要目的是为了用Example sql查询时直接调用不用手动在写；
     *               需要注意的是,Field 类必须要用mybatis generator 的而不能用java反射包下的
     * @Date: 21:44 2018/5/7
     * @Return: void
     */
    private void generateStaticProField(Field field,
            IntrospectedColumn introspectedColumn,
            TopLevelClass topLevelClass) {
        Field proField = new Field();
        proField.setVisibility(JavaVisibility.PUBLIC);
        proField.setStatic(true);
        proField.setFinal(true);
        // 给新生成的字段添加类型
        FullyQualifiedJavaType fullyQualifiedJavaType = new FullyQualifiedJavaType(
                "java.lang.String");
        // 添加类型
        proField.setType(fullyQualifiedJavaType);
        // 添加字段查询字符
        proField.setName("PRO_"
                + introspectedColumn.getActualColumnName().toUpperCase());
        // 添加初始值
        proField.setInitializationString("\"" + field.getName() + "\"");
        // TODO: 2018/2/11

        // proField.addJavaDocLine("/**\n\t *"+ introspectedColumn.getContext()+"\n\t
        // */");
        topLevelClass.addField(proField);
    }

    private void generateClassAnnotation(
            final TopLevelClass topLevelClass) {
        if(null == PropertiesUtil.CLASS_ANNOTATIONS
                || PropertiesUtil.CLASS_ANNOTATIONS.size() <= 0
                || null == PropertiesUtil.CLASS_ANNOTATION_PACKAGES
                || PropertiesUtil.CLASS_ANNOTATION_PACKAGES.size() <= 0) {
            return;
        }
        // 类注解添加
        PropertiesUtil.CLASS_ANNOTATIONS.stream().forEach(
                annotation -> topLevelClass.addAnnotation(annotation));
        // 引入自定义java文件包名，如：generateAnnotation方法中的@Encrypt
        PropertiesUtil.CLASS_ANNOTATION_PACKAGES.stream()
                .forEach(annotaionPackage -> topLevelClass
                        .addImportedType(annotaionPackage));
    }

    private void generateFieldAnnotation(Field field,
            final TopLevelClass topLevelClass) {
        if(null == PropertiesUtil.FIELD_ANNOTATION_TABLE_FIELD
                || PropertiesUtil.FIELD_ANNOTATION_TABLE_FIELD.size() <= 0
                || null == PropertiesUtil.FIELD_ANNOTATIONS
                || PropertiesUtil.FIELD_ANNOTATIONS.size() <= 0
                || null == PropertiesUtil.FIELD_ANNOTATION_PACKAGES
                || PropertiesUtil.FIELD_ANNOTATION_PACKAGES.size() <= 0) {
            return;
        }
        // 字段注解添加
        for(int i = 0; i < PropertiesUtil.FIELD_ANNOTATION_TABLE_FIELD
                .size(); i++) {
            // 字段与注解一一对应
            if(i > PropertiesUtil.FIELD_ANNOTATIONS.size() - 1) {
                break;
            }
            String singleField = PropertiesUtil.FIELD_ANNOTATION_TABLE_FIELD
                    .get(i);
            String singleAnnotations = PropertiesUtil.FIELD_ANNOTATIONS
                    .get(i);
            List<String> annotations = Arrays
                    .asList(singleAnnotations.split("&"));
            annotations.stream().forEach(item -> {
                if(singleField.equals(field.getName())) {
                    field.addAnnotation(item);
                }
            });
        }
        // 引入自定义java文件包名，如：generateAnnotation方法中的@Encrypt
        PropertiesUtil.FIELD_ANNOTATION_PACKAGES.stream()
                .forEach(annotaionPackage -> topLevelClass
                        .addImportedType(annotaionPackage));
    }

}
